const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// 引入bcrypt模块
const bcrypt = require('bcryptjs');
// 生成salt的迭代次数
const SALT_ROUNDS = 10;
// 最大登录失败次数
const MAX_LOGIN_ATTEMPTS = 5;
// 锁定时间2h 毫秒表示
const LOCK_TIME = 2 * 60 * 60 * 1000;

const userSchema = new Schema({
    username: {
        unique: true,
        required: true,
        type: String
    },
    email: {
        unique: true,
        required: true,
        type: String,
    },
    password: {
        unique: true,
        type: String
    },
    loginAttempts: {
        type: Number,
        required: true,
        default: 0
    },
    lockUnit: Number,
    meta: {
        createAt: {
            type: Date,
            default: Date.now()
        },
        updateAt: {
            type: Date,
            default: Date.now()
        }
    }
})

// 为模型添加虚拟字段 并不会存入数据库
/**
 * 如果lockUnit不为0，说明账号被锁定，同时需要判断锁定的时间有没有过了当前的时间 
 */
userSchema.virtual('isLocked').get(() => this.lockUnit && this.lockUnit > Date.now());

// 完成对单条数据save之前中间件的操作
userSchema.pre('save', function (next) {
    if (this.isNew) {
        this.meta.createAt = this.meta.updateAt = Date.now();
    } else {
        this.meta.updateAt = Date.now();
    }
    next();
})

// 完成对单条数据save之前中间件的操作 使用pre中间件在用户信息存储前进行密码加密
userSchema.pre('save', function (next) {
    let user = this;
    // 查看某个字段是否被更改 自带方法
    if (!user.isModified('password')) return next();
    // bcrypt 异步进行加密
    bcrypt.genSalt(SALT_ROUNDS, (err, salt) => {
        if (err) return next(err);
        bcrypt.hash(user.password, salt, (error, hash) => {
            if (err) return next(error);
            user.password = hash;
            next();
        })
    })
    next();
})

// 模型上的实例方法
userSchema.methods = {
    /**
     * 密码验证
     * _password: 未加密
     * password： 已加密
     */
    comparePassword: (_password, password) => {
        return new Promise((resolve, reject) => {
            bcrypt.compare(_password, password, (err, success) => {
                if (!err) {
                    resolve(success);
                } else {
                    reject(err);
                }
            })
        })
    },
    /**
     * 判断当前用户登录次数是否超出并锁定
     * Inc = increment
     */
    incLoginAttempts: () => new Promise((resolve, reject) => {
        // 过了锁定有效期
        if (this.lockUnit && this.lockUnit < Date.now()) {
            this.update({
                $set: {
                    loginAttempts: 1 // 设置为1
                },
                $unset: {
                    lockUnit: 1 // 删除目标键
                }
            }, err => {
                if (!err) resolve(trur);
                else reject(err);
            })
        } else {
            let updates = {
                $inc: {
                    loginAttempts: 1 // 加1
                }
            }
            // 尝试测试大于最大次数，并没有锁定时
            if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS && !this.isLocked) {
                updates.$set = {
                    lockUnit: Date.now() + LOCK_TIME // 设置锁定时长
                }
            }
            this.update(updates, err => {
                if (!err) resolve(trur);
                else reject(err);
            })
        }
    })
}
mongoose.model('User', userSchema);